home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d927.lha / Telnet / src / commands.c next >
C/C++ Source or Header  |  1993-10-07  |  47KB  |  2,219 lines

  1. /*
  2.  * Copyright (c) 1988, 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted provided
  6.  * that: (1) source distributions retain this entire copyright notice and
  7.  * comment, and (2) distributions including binaries display the following
  8.  * acknowledgement:  ``This product includes software developed by the
  9.  * University of California, Berkeley and its contributors'' in the
  10.  * documentation or other materials provided with the distribution and in
  11.  * all advertising materials mentioning features or use of this software.
  12.  * Neither the name of the University nor the names of its contributors may
  13.  * be used to endorse or promote products derived from this software without
  14.  * specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  16.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  17.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char sccsid[] = "@(#)commands.c    5.1 (Berkeley) 9/14/90";
  22. #endif /* not lint */
  23.  
  24. #include <sys/types.h>
  25. #include <string.h>
  26. #include <sys/socket.h>
  27. #ifdef AMI_TCP
  28. #include <bsdsocket.h>
  29. #else
  30. #include <ss/socket.h>
  31. #endif
  32. #include <netinet/in.h>
  33.  
  34. #include <signal.h>
  35. #include <netdb.h>
  36. #include <ctype.h>
  37. #ifndef AMI_TCP
  38. #include <pwd.h>
  39. #endif
  40.  
  41. #include <varargs.h>
  42. #include <arpa/telnet.h>
  43.  
  44. #include "general.h"
  45.  
  46. #include "ring.h"
  47.  
  48. #include "externs.h"
  49. #include "defines.h"
  50. #include "types.h"
  51.  
  52. char    *hostname;
  53. extern char *getenv();
  54. extern long bytesin;
  55. extern long bytesout;
  56. extern FILE *log_file;
  57.  
  58. #define Ambiguous(s)    ((char **)s == &ambiguous)
  59. static char *ambiguous;        /* special return value for command routines */
  60. static call();
  61.  
  62. typedef struct {
  63.     char    *name;        /* command name */
  64.     char    *help;        /* help string (NULL for no help) */
  65.     int    (*handler)();    /* routine which executes command */
  66.     int    needconnect;    /* Do we need to be connected to execute? */
  67. } Command;
  68.  
  69. static char line[256];
  70. static char saveline[256];
  71. static int margc;
  72. static char *margv[20];
  73.  
  74. /*
  75.  * Various utility routines.
  76.  */
  77.  
  78.  
  79. char    *h_errlist[] = {
  80.     "Error 0",
  81.     "Unknown host",                /* 1 HOST_NOT_FOUND */
  82.     "Host name lookup failure",        /* 2 TRY_AGAIN */
  83.     "Unknown server error",            /* 3 NO_RECOVERY */
  84.     "No address associated with name",    /* 4 NO_ADDRESS */
  85. };
  86. int    h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
  87.  
  88. int h_errno;        /* In some version of SunOS this is necessary */
  89.  
  90. /*
  91.  * herror --
  92.  *    print the error indicated by the h_errno value.
  93.  */
  94. herror(s)
  95.     char *s;
  96. {
  97.     if (s && *s) {
  98.         fprintf(stderr, "%s: ", s);
  99.     }
  100.     if ((h_errno < 0) || (h_errno >= h_nerr)) {
  101.         fprintf(stderr, "Unknown error\n");
  102.     } else if (h_errno == 0) {
  103. #if    defined(sun)
  104.         fprintf(stderr, "Host unknown\n");
  105. #endif    /* defined(sun) */
  106.     } else {
  107.         fprintf(stderr, "%s\n", h_errlist[h_errno]);
  108.     }
  109. }
  110.  
  111. static void
  112. makeargv()
  113. {
  114.     register char *cp, *cp2, c;
  115.     register char **argp = margv;
  116.  
  117.     margc = 0;
  118.     cp = line;
  119.     while (c = *cp) {
  120.     register int inquote = 0;
  121.     while (isspace(c))
  122.         c = *++cp;
  123.     if (c == '\0')
  124.         break;
  125.     *argp++ = cp;
  126.     margc += 1;
  127.     for (cp2 = cp; c != '\0'; c = *++cp) {
  128.         if (inquote) {
  129.         if (c == inquote) {
  130.             inquote = 0;
  131.             continue;
  132.         }
  133.         } else {
  134.         if (c == '\\') {
  135.             if ((c = *++cp) == '\0')
  136.             break;
  137.         } else if (c == '"') {
  138.             inquote = '"';
  139.             continue;
  140.         } else if (c == '\'') {
  141.             inquote = '\'';
  142.             continue;
  143.         } else if (isspace(c))
  144.             break;
  145.         }
  146.         *cp2++ = c;
  147.     }
  148.     *cp2 = '\0';
  149.     if (c == '\0')
  150.         break;
  151.     cp++;
  152.     }
  153.     *argp++ = 0;
  154. }
  155.  
  156.  
  157. static char **
  158. genget(name, table, next)
  159. char    *name;        /* name to match */
  160. char    **table;        /* name entry in table */
  161. char    **(*next)();    /* routine to return next entry in table */
  162. {
  163.     register char *p, *q;
  164.     register char **c, **found;
  165.     register int nmatches, longest;
  166.  
  167.     if (name == 0) {
  168.         return 0;
  169.     }
  170.     longest = 0;
  171.     nmatches = 0;
  172.     found = 0;
  173.     for (c = table; (p = *c) != 0; c = (*next)(c)) {
  174.         for (q = name;
  175.             (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
  176.             if (*q == 0)        /* exact match? */
  177.                 return (c);
  178.         if (!*q) {            /* the name was a prefix */
  179.             if (q - name > longest) {
  180.                 longest = q - name;
  181.                 nmatches = 1;
  182.                 found = c;
  183.             } else if (q - name == longest)
  184.                 nmatches++;
  185.         }
  186.     }
  187.     if (nmatches > 1)
  188.         return &ambiguous;
  189.     return (found);
  190. }
  191.  
  192. /*
  193.  * Make a character string into a number.
  194.  *
  195.  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
  196.  */
  197.  
  198. static
  199. special(s)
  200. register char *s;
  201. {
  202.     register char c;
  203.     char b;
  204.  
  205.     switch (*s) {
  206.     case '^':
  207.         b = *++s;
  208.         if (b == '?') {
  209.             c = b | 0x40;        /* DEL */
  210.         } else {
  211.             c = b & 0x1f;
  212.         }
  213.         break;
  214.     default:
  215.         c = *s;
  216.         break;
  217.     }
  218.     return c;
  219. }
  220.  
  221. /*
  222.  * Construct a control character sequence
  223.  * for a special character.
  224.  */
  225. static char *
  226. control(c)
  227.     register cc_t c;
  228. {
  229.     static char buf[5];
  230.  
  231.     if (c == 0x7f)
  232.         return ("^?");
  233.     if (c == (cc_t)_POSIX_VDISABLE) {
  234.         return "off";
  235.     }
  236.     if ((unsigned int)c >= 0x80) {
  237.         buf[0] = '\\';
  238.         buf[1] = ((c>>6)&07) + '0';
  239.         buf[2] = ((c>>3)&07) + '0';
  240.         buf[3] = (c&07) + '0';
  241.         buf[4] = 0;
  242.     } else if ((unsigned int)c >= 0x20) {
  243.         buf[0] = c;
  244.         buf[1] = 0;
  245.     } else {
  246.         buf[0] = '^';
  247.         buf[1] = '@'+c;
  248.         buf[2] = 0;
  249.     }
  250.     return (buf);
  251. }
  252.  
  253.  
  254.  
  255. /*
  256.  *    The following are data structures and routines for
  257.  *    the "send" command.
  258.  *
  259.  */
  260.  
  261. struct sendlist {
  262.     char    *name;        /* How user refers to it (case independent) */
  263.     char    *help;        /* Help information (0 ==> no help) */
  264.     int        (*handler)();    /* Routine to perform (for special ops) */
  265.     int        what;        /* Character to be sent (<0 ==> special) */
  266. };
  267.  
  268. #define    SENDQUESTION    -1
  269. #define    SENDESCAPE    -3
  270.  
  271. static struct sendlist Sendlist[] = {
  272.     { "ao",    "Send Telnet Abort output",        0,    AO },
  273.     { "ayt",    "Send Telnet 'Are You There'",        0,    AYT },
  274.     { "brk",    "Send Telnet Break",            0,    BREAK },
  275.     { "ec",    "Send Telnet Erase Character",        0,    EC },
  276.     { "el",    "Send Telnet Erase Line",        0,    EL },
  277.     { "escape",    "Send current escape character",    0,    SENDESCAPE },
  278.     { "ga",    "Send Telnet 'Go Ahead' sequence",    0,    GA },
  279.     { "ip",    "Send Telnet Interrupt Process",    0,    IP },
  280.     { "nop",    "Send Telnet 'No operation'",        0,    NOP },
  281.     { "eor",    "Send Telnet 'End of Record'",        0,    EOR },
  282.     { "abort",    "Send Telnet 'Abort Process'",        0,    ABORT },
  283.     { "susp",    "Send Telnet 'Suspend Process'",    0,    SUSP },
  284.     { "eof",    "Send Telnet End of File Character",    0,    xEOF },
  285.     { "synch",    "Perform Telnet 'Synch operation'",    dosynch, SYNCH },
  286.     { "getstatus", "Send request for STATUS",        get_status, 0 },
  287.     { "?",    "Display send options",            0,    SENDQUESTION },
  288.     { 0 }
  289. };
  290.  
  291. static struct sendlist Sendlist2[] = {        /* some synonyms */
  292.     { "break",        0, 0, BREAK },
  293.  
  294.     { "intp",        0, 0, IP },
  295.     { "interrupt",    0, 0, IP },
  296.     { "intr",        0, 0, IP },
  297.  
  298.     { "help",        0, 0, SENDQUESTION },
  299.  
  300.     { 0 }
  301. };
  302.  
  303. static char **
  304. getnextsend(name)
  305. char *name;
  306. {
  307.     struct sendlist *c = (struct sendlist *) name;
  308.  
  309.     return (char **) (c+1);
  310. }
  311.  
  312. static struct sendlist *
  313. getsend(name)
  314. char *name;
  315. {
  316.     struct sendlist *sl;
  317.  
  318.     if ((sl = (struct sendlist *)
  319.             genget(name, (char **) Sendlist, getnextsend)) != 0) {
  320.     return sl;
  321.     } else {
  322.     return (struct sendlist *)
  323.                 genget(name, (char **) Sendlist2, getnextsend);
  324.     }
  325. }
  326.  
  327. static
  328. sendcmd(argc, argv)
  329. int    argc;
  330. char    **argv;
  331. {
  332.     int what;        /* what we are sending this time */
  333.     int count;        /* how many bytes we are going to need to send */
  334.     int i;
  335.     int question = 0;    /* was at least one argument a question */
  336.     struct sendlist *s;    /* pointer to current command */
  337.  
  338.     if (argc < 2) {
  339.     printf("need at least one argument for 'send' command\n");
  340.     printf("'send ?' for help\n");
  341.     return 0;
  342.     }
  343.     /*
  344.      * First, validate all the send arguments.
  345.      * In addition, we see how much space we are going to need, and
  346.      * whether or not we will be doing a "SYNCH" operation (which
  347.      * flushes the network queue).
  348.      */
  349.     count = 0;
  350.     for (i = 1; i < argc; i++) {
  351.     s = getsend(argv[i]);
  352.     if (s == 0) {
  353.         printf("Unknown send argument '%s'\n'send ?' for help.\n",
  354.             argv[i]);
  355.         return 0;
  356.     } else if (Ambiguous(s)) {
  357.         printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
  358.             argv[i]);
  359.         return 0;
  360.     }
  361.     switch (s->what) {
  362.     case SENDQUESTION:
  363.         question = 1;
  364.         break;
  365.     case SENDESCAPE:
  366.         count += 1;
  367.         break;
  368.     case SYNCH:
  369.         count += 2;
  370.         break;
  371.     default:
  372.         count += 2;
  373.         break;
  374.     }
  375.     }
  376.     if (!connected) {
  377.     if (count)
  378.         printf("?Need to be connected first.\n");
  379.     if (question) {
  380.         for (s = Sendlist; s->name; s++)
  381.         if (s->help)
  382.             printf("%-15s %s\n", s->name, s->help);
  383.     } else
  384.         printf("'send ?' for help\n");
  385.     return !question;
  386.     }
  387.     /* Now, do we have enough room? */
  388.     if (NETROOM() < count) {
  389.     printf("There is not enough room in the buffer TO the network\n");
  390.     printf("to process your request.  Nothing will be done.\n");
  391.     printf("('send synch' will throw away most data in the network\n");
  392.     printf("buffer, if this might help.)\n");
  393.     return 0;
  394.     }
  395.     /* OK, they are all OK, now go through again and actually send */
  396.     for (i = 1; i < argc; i++) {
  397.     if ((s = getsend(argv[i])) == 0) {
  398.         fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
  399.         (void) quit();
  400.         /*NOTREACHED*/
  401.     }
  402.     if (s->handler) {
  403.         (*s->handler)(s);
  404.     } else {
  405.         switch (what = s->what) {
  406.         case SYNCH:
  407.         dosynch();
  408.         break;
  409.         case SENDQUESTION:
  410.         for (s = Sendlist; s->name; s++) {
  411.             if (s->help)
  412.             printf("%-15s %s\n", s->name, s->help);
  413.         }
  414.         question = 1;
  415.         break;
  416.         case SENDESCAPE:
  417.         NETADD(escape);
  418.         break;
  419.         default:
  420.         NET2ADD(IAC, what);
  421.         printoption("SENT", "IAC", what);
  422.         break;
  423.         }
  424.     }
  425.     }
  426.     return !question;
  427. }
  428.  
  429. /*
  430.  * The following are the routines and data structures referred
  431.  * to by the arguments to the "toggle" command.
  432.  */
  433.  
  434. static
  435. lclchars()
  436. {
  437.     donelclchars = 1;
  438.     return 1;
  439. }
  440.  
  441. static
  442. togdebug()
  443. {
  444.     if (debug) {
  445.     if (net > 0 && 
  446. #ifdef AMI_TCP
  447.     setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) 
  448. #else
  449.     SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) 
  450. #endif
  451.     < 0)
  452.         perror("setsockopt (SO_DEBUG)");
  453.     } else
  454.     printf("Cannot turn off socket debugging\n");
  455.     return 1;
  456. }
  457.  
  458.  
  459. static int
  460. togcrlf()
  461. {
  462.     if (crlf) {
  463.     printf("Will send carriage returns as telnet <CR><LF>.\n");
  464.     } else {
  465.     printf("Will send carriage returns as telnet <CR><NUL>.\n");
  466.     }
  467.     return 1;
  468. }
  469.  
  470. int binmode;
  471.  
  472. static int
  473. togbinary(val)
  474. int val;
  475. {
  476.     donebinarytoggle = 1;
  477.  
  478.     if (val >= 0) {
  479.     binmode = val;
  480.     } else {
  481.     if (my_want_state_is_will(TELOPT_BINARY) &&
  482.                 my_want_state_is_do(TELOPT_BINARY)) {
  483.         binmode = 1;
  484.     } else if (my_want_state_is_wont(TELOPT_BINARY) &&
  485.                 my_want_state_is_dont(TELOPT_BINARY)) {
  486.         binmode = 0;
  487.     }
  488.     val = binmode ? 0 : 1;
  489.     }
  490.  
  491.     if (val == 1) {
  492.     if (my_want_state_is_will(TELOPT_BINARY) &&
  493.                     my_want_state_is_do(TELOPT_BINARY)) {
  494.         printf("Already operating in binary mode with remote host.\n");
  495.     } else {
  496.         printf("Negotiating binary mode with remote host.\n");
  497.         tel_enter_binary(3);
  498.     }
  499.     } else {
  500.     if (my_want_state_is_wont(TELOPT_BINARY) &&
  501.                     my_want_state_is_dont(TELOPT_BINARY)) {
  502.         printf("Already in network ascii mode with remote host.\n");
  503.     } else {
  504.         printf("Negotiating network ascii mode with remote host.\n");
  505.         tel_leave_binary(3);
  506.     }
  507.     }
  508.     return 1;
  509. }
  510.  
  511. static int
  512. togrbinary(val)
  513. int val;
  514. {
  515.     donebinarytoggle = 1;
  516.  
  517.     if (val == -1)
  518.     val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
  519.  
  520.     if (val == 1) {
  521.     if (my_want_state_is_do(TELOPT_BINARY)) {
  522.         printf("Already receiving in binary mode.\n");
  523.     } else {
  524.         printf("Negotiating binary mode on input.\n");
  525.         tel_enter_binary(1);
  526.     }
  527.     } else {
  528.     if (my_want_state_is_dont(TELOPT_BINARY)) {
  529.         printf("Already receiving in network ascii mode.\n");
  530.     } else {
  531.         printf("Negotiating network ascii mode on input.\n");
  532.         tel_leave_binary(1);
  533.     }
  534.     }
  535.     return 1;
  536. }
  537.  
  538. static int
  539. togxbinary(val)
  540. int val;
  541. {
  542.     donebinarytoggle = 1;
  543.  
  544.     if (val == -1)
  545.     val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
  546.  
  547.     if (val == 1) {
  548.     if (my_want_state_is_will(TELOPT_BINARY)) {
  549.         printf("Already transmitting in binary mode.\n");
  550.     } else {
  551.         printf("Negotiating binary mode on output.\n");
  552.         tel_enter_binary(2);
  553.     }
  554.     } else {
  555.     if (my_want_state_is_wont(TELOPT_BINARY)) {
  556.         printf("Already transmitting in network ascii mode.\n");
  557.     } else {
  558.         printf("Negotiating network ascii mode on output.\n");
  559.         tel_leave_binary(2);
  560.     }
  561.     }
  562.     return 1;
  563. }
  564.  
  565.  
  566. extern int togglehelp();
  567. extern int slc_check();
  568.  
  569. struct togglelist {
  570.     char    *name;        /* name of toggle */
  571.     char    *help;        /* help message */
  572.     int        (*handler)();    /* routine to do actual setting */
  573.     int        *variable;
  574.     char    *actionexplanation;
  575. };
  576.  
  577. static struct togglelist Togglelist[] = {
  578.     { "autoflush",
  579.     "flushing of output when sending interrupt characters",
  580.         0,
  581.         &autoflush,
  582.             "flush output when sending interrupt characters" },
  583.     { "autosynch",
  584.     "automatic sending of interrupt characters in urgent mode",
  585.         0,
  586.         &autosynch,
  587.             "send interrupt characters in urgent mode" },
  588.     { "binary",
  589.     "sending and receiving of binary data",
  590.         togbinary,
  591.         0,
  592.             0 },
  593.     { "inbinary",
  594.     "receiving of binary data",
  595.         togrbinary,
  596.         0,
  597.             0 },
  598.     { "outbinary",
  599.     "sending of binary data",
  600.         togxbinary,
  601.         0,
  602.             0 },
  603.     { "crlf",
  604.     "sending carriage returns as telnet <CR><LF>",
  605.         togcrlf,
  606.         &crlf,
  607.             0 },
  608.     { "crmod",
  609.     "mapping of received carriage returns",
  610.         0,
  611.         &crmod,
  612.             "map carriage return on output" },
  613.     { "localchars",
  614.     "local recognition of certain control characters",
  615.         lclchars,
  616.         &localchars,
  617.             "recognize certain control characters" },
  618.     { " ", "", 0 },        /* empty line */
  619.     { "debug",
  620.     "debugging",
  621.         togdebug,
  622.         &debug,
  623.             "turn on socket level debugging" },
  624.     { "netdata",
  625.     "printing of hexadecimal network data (debugging)",
  626.         0,
  627.         &netdata,
  628.             "print hexadecimal representation of network traffic" },
  629.     { "prettydump",
  630.     "output of \"netdata\" to user readable format (debugging)",
  631.         0,
  632.         &prettydump,
  633.             "print user readable output for \"netdata\"" },
  634.     { "options",
  635.     "viewing of options processing (debugging)",
  636.         0,
  637.         &showoptions,
  638.             "show option processing" },
  639.     { "?",
  640.     0,
  641.         togglehelp },
  642.     { "help",
  643.     0,
  644.         togglehelp },
  645.     { 0 }
  646. };
  647.  
  648. static
  649. togglehelp()
  650. {
  651.     struct togglelist *c;
  652.  
  653.     for (c = Togglelist; c->name; c++) {
  654.     if (c->help) {
  655.         if (*c->help)
  656.         printf("%-15s toggle %s\n", c->name, c->help);
  657.         else
  658.         printf("\n");
  659.     }
  660.     }
  661.     printf("\n");
  662.     printf("%-15s %s\n", "?", "display help information");
  663.     return 0;
  664. }
  665.  
  666. static
  667. settogglehelp(set)
  668. int set;
  669. {
  670.     struct togglelist *c;
  671.  
  672.     for (c = Togglelist; c->name; c++) {
  673.     if (c->help) {
  674.         if (*c->help)
  675.         printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
  676.                         c->help);
  677.         else
  678.         printf("\n");
  679.     }
  680.     }
  681. }
  682.  
  683. static char **
  684. getnexttoggle(name)
  685. char *name;
  686. {
  687.     struct togglelist *c = (struct togglelist *) name;
  688.  
  689.     return (char **) (c+1);
  690. }
  691.  
  692. static struct togglelist *
  693. gettoggle(name)
  694. char *name;
  695. {
  696.     return (struct togglelist *)
  697.             genget(name, (char **) Togglelist, getnexttoggle);
  698. }
  699.  
  700. static
  701. toggle(argc, argv)
  702. int    argc;
  703. char    *argv[];
  704. {
  705.     int retval = 1;
  706.     char *name;
  707.     struct togglelist *c;
  708.  
  709.     if (argc < 2) {
  710.     fprintf(stderr,
  711.         "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
  712.     return 0;
  713.     }
  714.     argc--;
  715.     argv++;
  716.     while (argc--) {
  717.     name = *argv++;
  718.     c = gettoggle(name);
  719.     if (Ambiguous(c)) {
  720.         fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
  721.                     name);
  722.         return 0;
  723.     } else if (c == 0) {
  724.         fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
  725.                     name);
  726.         return 0;
  727.     } else {
  728.         if (c->variable) {
  729.         *c->variable = !*c->variable;        /* invert it */
  730.         if (c->actionexplanation) {
  731.             printf("%s %s.\n", *c->variable? "Will" : "Won't",
  732.                             c->actionexplanation);
  733.         }
  734.         }
  735.         if (c->handler) {
  736.         retval &= (*c->handler)(-1);
  737.         }
  738.     }
  739.     }
  740.     return retval;
  741. }
  742.  
  743. /*
  744.  * The following perform the "set" command.
  745.  */
  746.  
  747. struct setlist {
  748.     char *name;                /* name */
  749.     char *help;                /* help information */
  750.     void (*handler)();
  751.     cc_t *charp;            /* where it is located at */
  752. };
  753.  
  754. static struct setlist Setlist[] = {
  755.     { "escape",    "character to escape back to telnet command mode", 0, &escape },
  756.         { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
  757.     { " ", "" },
  758.     { 0 }
  759. };
  760.  
  761. static char **
  762. getnextset(name)
  763. char *name;
  764. {
  765.     struct setlist *c = (struct setlist *)name;
  766.  
  767.     return (char **) (c+1);
  768. }
  769.  
  770. static struct setlist *
  771. getset(name)
  772. char *name;
  773. {
  774.     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
  775. }
  776.  
  777. set_escape_char(s)
  778. char *s;
  779. {
  780.     escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
  781.     printf("escape character is '%s'.\n", control(escape));
  782. }
  783.  
  784. static
  785. setcmd(argc, argv)
  786. int    argc;
  787. char    *argv[];
  788. {
  789.     int value;
  790.     struct setlist *ct;
  791.     struct togglelist *c;
  792.  
  793.     if (argc < 2 || argc > 3) {
  794.     printf("Format is 'set Name Value'\n'set ?' for help.\n");
  795.     return 0;
  796.     }
  797.     if ((argc == 2) &&
  798.         ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
  799.     for (ct = Setlist; ct->name; ct++)
  800.         printf("%-15s %s\n", ct->name, ct->help);
  801.     printf("\n");
  802.     settogglehelp(1);
  803.     printf("%-15s %s\n", "?", "display help information");
  804.     return 0;
  805.     }
  806.  
  807.     ct = getset(argv[1]);
  808.     if (ct == 0) {
  809.     c = gettoggle(argv[1]);
  810.     if (c == 0) {
  811.         fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
  812.             argv[1]);
  813.         return 0;
  814.     } else if (Ambiguous(c)) {
  815.         fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
  816.             argv[1]);
  817.         return 0;
  818.     }
  819.     if (c->variable) {
  820.         if ((argc == 2) || (strcmp("on", argv[2]) == 0))
  821.         *c->variable = 1;
  822.         else if (strcmp("off", argv[2]) == 0)
  823.         *c->variable = 0;
  824.         else {
  825.         printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
  826.         return 0;
  827.         }
  828.         if (c->actionexplanation) {
  829.         printf("%s %s.\n", *c->variable? "Will" : "Won't",
  830.                             c->actionexplanation);
  831.         }
  832.     }
  833.     if (c->handler)
  834.         (*c->handler)(1);
  835.     } else if (argc != 3) {
  836.     printf("Format is 'set Name Value'\n'set ?' for help.\n");
  837.     return 0;
  838.     } else if (Ambiguous(ct)) {
  839.     fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
  840.             argv[1]);
  841.     return 0;
  842.     } else if (ct->handler) {
  843.     (*ct->handler)(argv[2]);
  844.     printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
  845.     } else {
  846.     if (strcmp("off", argv[2])) {
  847.         value = special(argv[2]);
  848.     } else {
  849.         value = _POSIX_VDISABLE;
  850.     }
  851.     *(ct->charp) = (cc_t)value;
  852.     printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
  853.     }
  854.     slc_check();
  855.     return 1;
  856. }
  857.  
  858. static
  859. unsetcmd(argc, argv)
  860. int    argc;
  861. char    *argv[];
  862. {
  863.     struct setlist *ct;
  864.     struct togglelist *c;
  865.     register char *name;
  866.  
  867.     if (argc < 2) {
  868.     fprintf(stderr,
  869.         "Need an argument to 'unset' command.  'unset ?' for help.\n");
  870.     return 0;
  871.     }
  872.     if ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help"))) {
  873.     for (ct = Setlist; ct->name; ct++)
  874.         printf("%-15s %s\n", ct->name, ct->help);
  875.     printf("\n");
  876.     settogglehelp(0);
  877.     printf("%-15s %s\n", "?", "display help information");
  878.     return 0;
  879.     }
  880.  
  881.     argc--;
  882.     argv++;
  883.     while (argc--) {
  884.     name = *argv++;
  885.     ct = getset(name);
  886.     if (ct == 0) {
  887.         c = gettoggle(name);
  888.         if (c == 0) {
  889.         fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
  890.             name);
  891.         return 0;
  892.         } else if (Ambiguous(c)) {
  893.         fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
  894.             name);
  895.         return 0;
  896.         }
  897.         if (c->variable) {
  898.         *c->variable = 0;
  899.         if (c->actionexplanation) {
  900.             printf("%s %s.\n", *c->variable? "Will" : "Won't",
  901.                             c->actionexplanation);
  902.         }
  903.         }
  904.         if (c->handler)
  905.         (*c->handler)(0);
  906.     } else if (Ambiguous(ct)) {
  907.         fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
  908.             name);
  909.         return 0;
  910.     } else if (ct->handler) {
  911.         (*ct->handler)(0);
  912.         printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
  913.     } else {
  914.         *(ct->charp) = _POSIX_VDISABLE;
  915.         printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
  916.     }
  917.     }
  918.     return 1;
  919. }
  920.  
  921. /*
  922.  * The following are the data structures and routines for the
  923.  * 'mode' command.
  924.  */
  925.  
  926. static
  927. dolinemode()
  928. {
  929.     send_will(TELOPT_LINEMODE, 1);
  930.     send_dont(TELOPT_ECHO, 1);
  931.     return 1;
  932. }
  933.  
  934. static
  935. docharmode()
  936. {
  937.     send_wont(TELOPT_LINEMODE, 1);
  938.     send_do(TELOPT_ECHO, 1);
  939.     return 1;
  940. }
  941.  
  942. setmode(bit)
  943. {
  944.     return dolmmode(bit, 1);
  945. }
  946.  
  947. clearmode(bit)
  948. {
  949.     return dolmmode(bit, 0);
  950. }
  951.  
  952. dolmmode(bit, on)
  953. int bit, on;
  954. {
  955.     char c;
  956.     extern int linemode;
  957.  
  958.     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
  959.     printf("?Need to have LINEMODE option enabled first.\n");
  960.     printf("'mode ?' for help.\n");
  961.     return 0;
  962.     }
  963.  
  964.     if (on)
  965.     c = (linemode | bit);
  966.     else
  967.     c = (linemode & ~bit);
  968.     lm_mode(&c, 1, 1);
  969.     return 1;
  970. }
  971.  
  972. struct modelist {
  973.     char    *name;        /* command name */
  974.     char    *help;        /* help string */
  975.     int    (*handler)();    /* routine which executes command */
  976.     int    needconnect;    /* Do we need to be connected to execute? */
  977.     int    arg1;
  978. };
  979.  
  980. extern int modehelp();
  981.  
  982. static struct modelist ModeList[] = {
  983.     { "character", "Disable LINEMODE option",    docharmode, 1 },
  984.     { "line",    "Enable LINEMODE option",    dolinemode, 1 },
  985.     { "", "", 0 },
  986.     { "",    "These require the LINEMODE option to be enabled", 0 },
  987.     { "isig",    "Enable signal trapping",    setmode, 1, MODE_TRAPSIG },
  988.     { "+isig",    0,                setmode, 1, MODE_TRAPSIG },
  989.     { "-isig",    "Disable signal trapping",    clearmode, 1, MODE_TRAPSIG },
  990.     { "edit",    "Enable character editing",    setmode, 1, MODE_EDIT },
  991.     { "+edit",    0,                setmode, 1, MODE_EDIT },
  992.     { "-edit",    "Disable character editing",    clearmode, 1, MODE_EDIT },
  993.     { "softtabs", "Enable tab expansion",    setmode, 1, MODE_SOFT_TAB },
  994.     { "+softtabs", 0,                setmode, 1, MODE_SOFT_TAB },
  995.     { "-softtabs", "Disable character editing",    clearmode, 1, MODE_SOFT_TAB },
  996.     { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
  997.     { "+litecho", 0,                setmode, 1, MODE_LIT_ECHO },
  998.     { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
  999.     { "help",    0,                modehelp, 0 },
  1000.     { "", "", 0 },
  1001.     { "?",    "Print help information",    modehelp, 0 },
  1002.     { 0 },
  1003. };
  1004.  
  1005. static char **
  1006. getnextmode(name)
  1007. char *name;
  1008. {
  1009.     return (char **) (((struct modelist *)name)+1);
  1010. }
  1011.  
  1012. static struct modelist *
  1013. getmodecmd(name)
  1014. char *name;
  1015. {
  1016.     return (struct modelist *) genget(name, (char **) ModeList, getnextmode);
  1017. }
  1018.  
  1019. modehelp()
  1020. {
  1021.     struct modelist *mt;
  1022.  
  1023.     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
  1024.     for (mt = ModeList; mt->name; mt++) {
  1025.     if (mt->help) {
  1026.         if (*mt->help)
  1027.         printf("%-15s %s\n", mt->name, mt->help);
  1028.         else
  1029.         printf("\n");
  1030.     }
  1031.     }
  1032.     return 0;
  1033. }
  1034.  
  1035. static
  1036. modecmd(argc, argv)
  1037. int    argc;
  1038. char    *argv[];
  1039. {
  1040.     struct modelist *mt;
  1041.  
  1042.     if (argc != 2) {
  1043.     printf("'mode' command requires an argument\n");
  1044.     printf("'mode ?' for help.\n");
  1045.     } else if ((mt = getmodecmd(argv[1])) == 0) {
  1046.     fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
  1047.     } else if (Ambiguous(mt)) {
  1048.     fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
  1049.     } else if (mt->needconnect && !connected) {
  1050.     printf("?Need to be connected first.\n");
  1051.     printf("'mode ?' for help.\n");
  1052.     } else if (mt->handler) {
  1053.     return (*mt->handler)(mt->arg1);
  1054.     }
  1055.     return 0;
  1056. }
  1057.  
  1058. /*
  1059.  * The following data structures and routines implement the
  1060.  * "display" command.
  1061.  */
  1062.  
  1063. static
  1064. display(argc, argv)
  1065. int    argc;
  1066. char    *argv[];
  1067. {
  1068. #define    dotog(tl)    if (tl->variable && tl->actionexplanation) { \
  1069.                 if (*tl->variable) { \
  1070.                 printf("will"); \
  1071.                 } else { \
  1072.                 printf("won't"); \
  1073.                 } \
  1074.                 printf(" %s.\n", tl->actionexplanation); \
  1075.             }
  1076.  
  1077. #define    doset(sl)   if (sl->name && *sl->name != ' ') { \
  1078.             if (sl->handler == 0) \
  1079.                 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
  1080.             else \
  1081.                 printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
  1082.             }
  1083.  
  1084.     struct togglelist *tl;
  1085.     struct setlist *sl;
  1086.  
  1087.     if (argc == 1) {
  1088.     for (tl = Togglelist; tl->name; tl++) {
  1089.         dotog(tl);
  1090.     }
  1091.     printf("\n");
  1092.     for (sl = Setlist; sl->name; sl++) {
  1093.         doset(sl);
  1094.     }
  1095.     } else {
  1096.     int i;
  1097.  
  1098.     for (i = 1; i < argc; i++) {
  1099.         sl = getset(argv[i]);
  1100.         tl = gettoggle(argv[i]);
  1101.         if (Ambiguous(sl) || Ambiguous(tl)) {
  1102.         printf("?Ambiguous argument '%s'.\n", argv[i]);
  1103.         return 0;
  1104.         } else if (!sl && !tl) {
  1105.         printf("?Unknown argument '%s'.\n", argv[i]);
  1106.         return 0;
  1107.         } else {
  1108.         if (tl) {
  1109.             dotog(tl);
  1110.         }
  1111.         if (sl) {
  1112.             doset(sl);
  1113.         }
  1114.         }
  1115.     }
  1116.     }
  1117. /*@*/optionstatus();
  1118.     return 1;
  1119. #undef    doset
  1120. #undef    dotog
  1121. }
  1122.  
  1123. /*
  1124.  * The following are the data structures, and many of the routines,
  1125.  * relating to command processing.
  1126.  */
  1127.  
  1128. /*
  1129.  * Set the escape character.
  1130.  */
  1131. static
  1132. setescape(argc, argv)
  1133.     int argc;
  1134.     char *argv[];
  1135. {
  1136.     register char *arg;
  1137.     char buf[50];
  1138.  
  1139.     printf(
  1140.         "Deprecated usage - please use 'set escape%s%s' in the future.\n",
  1141.                 (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
  1142.     if (argc > 2)
  1143.         arg = argv[1];
  1144.     else {
  1145.         printf("new escape character: ");
  1146.         (void) gets(buf);
  1147.         arg = buf;
  1148.     }
  1149.     if (arg[0] != '\0')
  1150.         escape = arg[0];
  1151.         printf("Escape character is '%s'.\n", control(escape));
  1152.     (void) fflush(stdout);
  1153.     return 1;
  1154. }
  1155.  
  1156. /*VARARGS*/
  1157. static
  1158. togcrmod()
  1159. {
  1160.     crmod = !crmod;
  1161.     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
  1162.     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
  1163.     (void) fflush(stdout);
  1164.     return 1;
  1165. }
  1166.  
  1167. /*VARARGS*/
  1168. suspend()
  1169. {
  1170.     return 1;
  1171. }
  1172.  
  1173. /*VARARGS*/
  1174. static
  1175. bye(argc, argv)
  1176. int    argc;        /* Number of arguments */
  1177. char    *argv[];    /* arguments */
  1178. {
  1179.     if (connected) {
  1180.     (void) shutdown(net, 2);
  1181.     printf("Connection closed.\n");
  1182.     (void) NetClose(net);
  1183.     fprintf(log_file,"%s %d\n",hostname,bytesin+bytesout);
  1184.     connected = 0;
  1185.     /* reset options */
  1186.     tninit();
  1187.     }
  1188.     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
  1189.     longjmp(toplevel, 1);
  1190.     /* NOTREACHED */
  1191.     }
  1192.     return 1;            /* Keep lint, etc., happy */
  1193. }
  1194.  
  1195. /*VARARGS*/
  1196. quit()
  1197. {
  1198.     (void) call(bye, "bye", "fromquit", 0);
  1199.     Exit(0);
  1200.     /*NOTREACHED*/
  1201. }
  1202.  
  1203. /*
  1204.  * The SLC command.
  1205.  */
  1206.  
  1207. struct slclist {
  1208.     char    *name;
  1209.     char    *help;
  1210.     int    (*handler)();
  1211.     int    arg;
  1212. };
  1213.  
  1214. extern int slc_help();
  1215. extern int slc_mode_export(), slc_mode_import(), slcstate();
  1216.  
  1217. struct slclist SlcList[] = {
  1218.     { "export",    "Use local special character definitions",
  1219.                         slc_mode_export,    0 },
  1220.     { "import",    "Use remote special character definitions",
  1221.                         slc_mode_import,    1 },
  1222.     { "check",    "Verify remote special character definitions",
  1223.                         slc_mode_import,    0 },
  1224.     { "help",    0,                slc_help,        0 },
  1225.     { "?",    "Print help information",    slc_help,        0 },
  1226.     { 0 },
  1227. };
  1228.  
  1229. static
  1230. slc_help()
  1231. {
  1232.     struct slclist *c;
  1233.  
  1234.     for (c = SlcList; c->name; c++) {
  1235.     if (c->help) {
  1236.         if (*c->help)
  1237.         printf("%-15s %s\n", c->name, c->help);
  1238.         else
  1239.         printf("\n");
  1240.     }
  1241.     }
  1242. }
  1243.  
  1244. static char **
  1245. getnextslc(name)
  1246. char *name;
  1247. {
  1248.     return (char **)(((struct slclist *)name)+1);
  1249. }
  1250.  
  1251. static struct slclist *
  1252. getslc(name)
  1253. char *name;
  1254. {
  1255.     return (struct slclist *)genget(name, (char **) SlcList, getnextslc);
  1256. }
  1257.  
  1258. static
  1259. slccmd(argc, argv)
  1260. int    argc;
  1261. char    *argv[];
  1262. {
  1263.     struct slclist *c;
  1264.  
  1265.     if (argc != 2) {
  1266.     fprintf(stderr,
  1267.         "Need an argument to 'slc' command.  'slc ?' for help.\n");
  1268.     return 0;
  1269.     }
  1270.     c = getslc(argv[1]);
  1271.     if (c == 0) {
  1272.         fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
  1273.                     argv[1]);
  1274.         return 0;
  1275.     }
  1276.     if (Ambiguous(c)) {
  1277.         fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
  1278.                     argv[1]);
  1279.         return 0;
  1280.     }
  1281.     (*c->handler)(c->arg);
  1282.     slcstate();
  1283.     return 1;
  1284. }
  1285.  
  1286. /*
  1287.  * The ENVIRON command.
  1288.  */
  1289.  
  1290. struct envlist {
  1291.     char    *name;
  1292.     char    *help;
  1293.     int    (*handler)();
  1294.     int    narg;
  1295. };
  1296.  
  1297. extern struct env_lst *env_define();
  1298. extern int env_undefine();
  1299. extern int env_export(), env_unexport();
  1300. extern int env_send(), env_list(), env_help();
  1301.  
  1302. struct envlist EnvList[] = {
  1303.     { "define",    "Define an environment variable",
  1304.                         (int (*)())env_define,    2 },
  1305.     { "undefine", "Undefine an environment variable",
  1306.                         env_undefine,    1 },
  1307.     { "export",    "Mark an environment variable for automatic export",
  1308.                         env_export,    1 },
  1309.     { "unexport", "Dont mark an environment variable for automatic export",
  1310.                         env_unexport,    1 },
  1311.     { "send",    "Send an environment variable", env_send,    1 },
  1312.     { "list",    "List the current environment variables",
  1313.                         env_list,    0 },
  1314.     { "help",    0,                env_help,        0 },
  1315.     { "?",    "Print help information",    env_help,        0 },
  1316.     { 0 },
  1317. };
  1318.  
  1319. static
  1320. env_help()
  1321. {
  1322.     struct envlist *c;
  1323.  
  1324.     for (c = EnvList; c->name; c++) {
  1325.     if (c->help) {
  1326.         if (*c->help)
  1327.         printf("%-15s %s\n", c->name, c->help);
  1328.         else
  1329.         printf("\n");
  1330.     }
  1331.     }
  1332. }
  1333.  
  1334. static char **
  1335. getnextenv(name)
  1336. char *name;
  1337. {
  1338.     return (char **)(((struct envlist *)name)+1);
  1339. }
  1340.  
  1341. static struct envlist *
  1342. getenvcmd(name)
  1343. char *name;
  1344. {
  1345.     return (struct envlist *)genget(name, (char **) EnvList, getnextenv);
  1346. }
  1347.  
  1348. env_cmd(argc, argv)
  1349. int    argc;
  1350. char    *argv[];
  1351. {
  1352.     struct envlist *c;
  1353.  
  1354.     if (argc < 2) {
  1355.     fprintf(stderr,
  1356.         "Need an argument to 'environ' command.  'environ ?' for help.\n");
  1357.     return 0;
  1358.     }
  1359.     c = getenvcmd(argv[1]);
  1360.     if (c == 0) {
  1361.         fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
  1362.                     argv[1]);
  1363.         return 0;
  1364.     }
  1365.     if (Ambiguous(c)) {
  1366.         fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
  1367.                     argv[1]);
  1368.         return 0;
  1369.     }
  1370.     if (c->narg + 2 != argc) {
  1371.     fprintf(stderr,
  1372.         "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
  1373.         c->narg < argc + 2 ? "only " : "",
  1374.         c->narg, c->narg == 1 ? "" : "s", c->name);
  1375.     return 0;
  1376.     }
  1377.     (void)(*c->handler)(argv[2], argv[3]);
  1378.     return 1;
  1379. }
  1380.  
  1381. struct env_lst {
  1382.     struct env_lst *next;    /* pointer to next structure */
  1383.     struct env_lst *prev;    /* pointer to next structure */
  1384.     char *var;        /* pointer to variable name */
  1385.     char *value;        /* pointer to varialbe value */
  1386.     int export;        /* 1 -> export with default list of variables */
  1387. };
  1388.  
  1389. struct env_lst envlisthead;
  1390.  
  1391. struct env_lst *
  1392. env_find(var)
  1393. char *var;
  1394. {
  1395.     register struct env_lst *ep;
  1396.  
  1397.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1398.         if (strcmp(ep->var, var) == 0)
  1399.             return(ep);
  1400.     }
  1401.     return(NULL);
  1402. }
  1403.  
  1404. env_init()
  1405. {
  1406.     register char **epp, *cp;
  1407.     register struct env_lst *ep;
  1408.  
  1409.     /*
  1410.      * If USER is not defined, but LOGNAME is, then add
  1411.      * USER with the value from LOGNAME.  By default, we
  1412.      * don't export the USER variable.
  1413.      */
  1414.     if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
  1415.         env_define("USER", ep->value);
  1416.         env_unexport("USER");
  1417.     }
  1418.     env_export("DISPLAY");
  1419.     env_export("PRINTER");
  1420. }
  1421.  
  1422. struct env_lst *
  1423. env_define(var, value)
  1424. char *var, *value;
  1425. {
  1426.     register struct env_lst *ep;
  1427.     extern char *strdup();
  1428.  
  1429.     if (ep = env_find(var)) {
  1430.         if (ep->var)
  1431.             free(ep->var);
  1432.         if (ep->value)
  1433.             free(ep->value);
  1434.     } else {
  1435.         ep = (struct env_lst *)malloc(sizeof(struct env_lst));
  1436.         ep->next = envlisthead.next;
  1437.         envlisthead.next = ep;
  1438.         ep->prev = &envlisthead;
  1439.         if (ep->next)
  1440.             ep->next->prev = ep;
  1441.     }
  1442.     ep->export = 1;
  1443.     ep->var = strdup(var);
  1444.     ep->value = strdup(value);
  1445.     return(ep);
  1446. }
  1447.  
  1448. env_undefine(var)
  1449. char *var;
  1450. {
  1451.     register struct env_lst *ep;
  1452.  
  1453.     if (ep = env_find(var)) {
  1454.         ep->prev->next = ep->next;
  1455.         if (ep->next)
  1456.             ep->next->prev = ep->prev;
  1457.         if (ep->var)
  1458.             free(ep->var);
  1459.         if (ep->value)
  1460.             free(ep->value);
  1461.         free(ep);
  1462.     }
  1463. }
  1464.  
  1465. env_export(var)
  1466. char *var;
  1467. {
  1468.     register struct env_lst *ep;
  1469.  
  1470.     if (ep = env_find(var))
  1471.         ep->export = 1;
  1472. }
  1473.  
  1474. env_unexport(var)
  1475. char *var;
  1476. {
  1477.     register struct env_lst *ep;
  1478.  
  1479.     if (ep = env_find(var))
  1480.         ep->export = 0;
  1481. }
  1482.  
  1483. env_send(var)
  1484. char *var;
  1485. {
  1486.     register struct env_lst *ep;
  1487.  
  1488.         if (my_state_is_wont(TELOPT_ENVIRON)) {
  1489.         fprintf(stderr,
  1490.             "Cannot send '%s': Telnet ENVIRON option not enabled\n",
  1491.                                     var);
  1492.         return;
  1493.     }
  1494.     ep = env_find(var);
  1495.     if (ep == 0) {
  1496.         fprintf(stderr, "Cannot send '%s': variable not defined\n",
  1497.                                     var);
  1498.         return;
  1499.     }
  1500.     env_opt_start_info();
  1501.     env_opt_add(ep->var);
  1502.     env_opt_end(0);
  1503. }
  1504.  
  1505. env_list()
  1506. {
  1507.     register struct env_lst *ep;
  1508.  
  1509.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1510.         printf("%c %-20s %s\n", ep->export ? '*' : ' ',
  1511.                     ep->var, ep->value);
  1512.     }
  1513. }
  1514.  
  1515. char *
  1516. env_default(init)
  1517. {
  1518.     static struct env_lst *nep = NULL;
  1519.  
  1520.     if (init) {
  1521.         nep = &envlisthead;
  1522.         return;
  1523.     }
  1524.     if (nep) {
  1525.         while (nep = nep->next) {
  1526.             if (nep->export)
  1527.                 return(nep->var);
  1528.         }
  1529.     }
  1530.     return(NULL);
  1531. }
  1532.  
  1533. char *
  1534. env_getvalue(var)
  1535. char *var;
  1536. {
  1537.     register struct env_lst *ep;
  1538.  
  1539.     if (ep = env_find(var))
  1540.         return(ep->value);
  1541.     return(NULL);
  1542. }
  1543.  
  1544. /*
  1545.  * Print status about the connection.
  1546.  */
  1547. /*ARGSUSED*/
  1548. static
  1549. status(argc, argv)
  1550. int    argc;
  1551. char    *argv[];
  1552. {
  1553.     if (connected) {
  1554.     printf("Connected to %s.\n", hostname);
  1555.     if ((argc < 2) || strcmp(argv[1], "notmuch")) {
  1556.         int mode = getconnmode();
  1557.  
  1558.         if (my_want_state_is_will(TELOPT_LINEMODE)) {
  1559.         printf("Operating with LINEMODE option\n");
  1560.         printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
  1561.         printf("%s catching of signals\n",
  1562.                     (mode&MODE_TRAPSIG) ? "Local" : "No");
  1563.         slcstate();
  1564.         } else {
  1565.         printf("Operating in single character mode\n");
  1566.         if (localchars)
  1567.             printf("Catching signals locally\n");
  1568.         }
  1569.         printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
  1570.         if (my_want_state_is_will(TELOPT_LFLOW))
  1571.         printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
  1572.     }
  1573.     } else {
  1574.     printf("No connection.\n");
  1575.     }
  1576.     printf("Escape character is '%s'.\n", control(escape));
  1577.     (void) fflush(stdout);
  1578.     return 1;
  1579. }
  1580.  
  1581.  
  1582. extern    int autologin;
  1583.  
  1584. int
  1585. tn(argc, argv)
  1586.     int argc;
  1587.     char *argv[];
  1588. {
  1589.     register struct hostent *host = 0;
  1590.     struct sockaddr_in sin;
  1591.     struct servent *sp = 0;
  1592.     static char    hnamebuf[32];
  1593.     unsigned long temp, inet_addr();
  1594.     extern char *inet_ntoa();
  1595. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1596.     char *srp = 0, *strrchr();
  1597.     unsigned long sourceroute(), srlen;
  1598. #endif
  1599.     char *cmd, *hostp = 0, *portp = 0, *user = 0;
  1600.  
  1601.     /* clear the socket address prior to use */
  1602.     bzero((char *)&sin, sizeof(sin));
  1603.  
  1604.     if (connected) {
  1605.     printf("?Already connected to %s\n", hostname);
  1606.     return 0;
  1607.     }
  1608.     if (argc < 2) {
  1609.     (void) strcpy(line, "Connect ");
  1610.     printf("(to) ");
  1611.     (void) gets(&line[strlen(line)]);
  1612.     makeargv();
  1613.     argc = margc;
  1614.     argv = margv;
  1615.     }
  1616.     cmd = *argv;
  1617.     --argc; ++argv;
  1618.     while (argc) {
  1619.     if (strcmp(*argv, "-l") == 0) {
  1620.         --argc; ++argv;
  1621.         if (argc == 0)
  1622.         goto usage;
  1623.         user = *argv++;
  1624.         --argc;
  1625.         continue;
  1626.     }
  1627.     if (strcmp(*argv, "-a") == 0) {
  1628.         --argc; ++argv;
  1629.         autologin = 1;
  1630.         continue;
  1631.     }
  1632.     if (hostp == 0) {
  1633.         hostp = *argv++;
  1634.         --argc;
  1635.         continue;
  1636.     }
  1637.     if (portp == 0) {
  1638.         portp = *argv++;
  1639.         --argc;
  1640.         continue;
  1641.     }
  1642.     usage:
  1643.     printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
  1644.     return 0;
  1645.     }
  1646. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1647.     if (hostp[0] == '@' || hostp[0] == '!') {
  1648.     if ((hostname = strrchr(hostp, ':')) == NULL)
  1649.         hostname = strrchr(hostp, '@');
  1650.     hostname++;
  1651.     srp = 0;
  1652.     temp = sourceroute(hostp, &srp, &srlen);
  1653.     if (temp == 0) {
  1654.         herror(srp);
  1655.         return 0;
  1656.     } else if (temp == -1) {
  1657.         printf("Bad source route option: %s\n", hostp);
  1658.         return 0;
  1659.     } else {
  1660.         sin.sin_addr.s_addr = temp;
  1661.         sin.sin_family = AF_INET;
  1662.     }
  1663.     } else {
  1664. #endif
  1665.     temp = inet_addr(hostp);
  1666.     if (temp != (unsigned long) -1) {
  1667.         sin.sin_addr.s_addr = temp;
  1668.         sin.sin_family = AF_INET;
  1669.         (void) strcpy(hnamebuf, hostp);
  1670.         hostname = hnamebuf;
  1671.     } else {
  1672.         host = gethostbyname(hostp);
  1673.         if (host) {
  1674.         sin.sin_family = host->h_addrtype;
  1675.         memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
  1676.         hostname = host->h_name;
  1677.         } else {
  1678.         herror(hostp);
  1679.         return 0;
  1680.         }
  1681.     }
  1682. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1683.     }
  1684. #endif
  1685.     if (portp) {
  1686.     if (*portp == '-') {
  1687.         portp++;
  1688.         telnetport = 1;
  1689.     } else
  1690.         telnetport = 0;
  1691.     sin.sin_port = atoi(portp);
  1692.     if (sin.sin_port == 0) {
  1693.         sp = getservbyname(portp, "tcp");
  1694.         if (sp)
  1695.         sin.sin_port = sp->s_port;
  1696.         else {
  1697.         printf("%s: bad port number\n", portp);
  1698.         return 0;
  1699.         }
  1700.     } else {
  1701. #if    !defined(htons)
  1702.         u_short htons();
  1703. #endif    /* !defined(htons) */
  1704.         sin.sin_port = htons(sin.sin_port);
  1705.     }
  1706.     } else {
  1707.     if (sp == 0) {
  1708.         sp = getservbyname("telnet", "tcp");
  1709.         if (sp == 0) {
  1710.         fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
  1711.         return 0;
  1712.         }
  1713.         sin.sin_port = sp->s_port;
  1714.     }
  1715.     telnetport = 1;
  1716.     }
  1717.     bytesin = 0;
  1718.     bytesout = 0;
  1719. #ifdef AMI_TCP    
  1720.     printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
  1721. #else
  1722.     printf("Trying %s...\n", inet_ntoa(sin.sin_addr.s_addr));
  1723. #endif
  1724.     do {
  1725.     net = socket(AF_INET, SOCK_STREAM, 0);
  1726.     if (net < 0) {
  1727.         perror("telnet: socket");
  1728.         return 0;
  1729.     }
  1730. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1731.     if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
  1732.         perror("setsockopt (IP_OPTIONS)");
  1733. #endif
  1734.  
  1735.     if (debug && 
  1736. #ifdef AMI_TCP
  1737.     setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug,sizeof(debug)) 
  1738. #else
  1739.     SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) 
  1740. #endif
  1741.     < 0) {
  1742.         perror("setsockopt (SO_DEBUG)");
  1743.     }
  1744.  
  1745.     if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  1746.         perror("telnet: Unable to connect to remote host");
  1747.         return 0;
  1748.     }
  1749.     connected++;
  1750.     } while (connected == 0);
  1751.     cmdrc(hostp, hostname);
  1752.     if (autologin && user == NULL) {
  1753. #ifdef AMI_TCP
  1754.     user = getenv("USER");
  1755. #else
  1756.     struct passwd *pw;
  1757.     if (user == NULL ||
  1758.         (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
  1759.         if (pw = getpwuid(getuid()))
  1760.             user = pw->pw_name;
  1761.         else
  1762.             user = NULL;
  1763.     }
  1764. #endif
  1765.     }
  1766.     if (user) {
  1767.     env_define("USER", user);
  1768.     env_export("USER");
  1769.     }
  1770.     (void) call(status, "status", "notmuch", 0);
  1771.     if (setjmp(peerdied) == 0)
  1772.     telnet();
  1773.     (void) NetClose(net);
  1774.     fprintf(log_file,"%s %d\n",hostname,bytesin+bytesout);
  1775.     ExitString("Connection closed by foreign host.\n",1);
  1776.     /*NOTREACHED*/
  1777. }
  1778.  
  1779. controld()
  1780.  
  1781. {
  1782.         NETADD(4);
  1783. }
  1784.  
  1785. #define HELPINDENT (sizeof ("connect"))
  1786.  
  1787. static char
  1788.     openhelp[] =    "connect to a site",
  1789.     closehelp[] =    "close current connection",
  1790.     quithelp[] =    "exit telnet",
  1791.     statushelp[] =    "print status information",
  1792.     helphelp[] =    "print help information",
  1793.     sendhelp[] =    "transmit special characters ('send ?' for more)",
  1794.     sethelp[] =     "set operating parameters ('set ?' for more)",
  1795.     unsethelp[] =     "unset operating parameters ('unset ?' for more)",
  1796.     togglestring[] ="toggle operating parameters ('toggle ?' for more)",
  1797.     slchelp[] =    "change state of special charaters ('slc ?' for more)",
  1798.     displayhelp[] =    "display operating parameters",
  1799.     controlhelp[] = "send a control-D to host",
  1800.     envhelp[] =    "change environment variables ('environ ?' for more)",
  1801.     modestring[] = "try to enter line or character mode ('mode ?' for more)";
  1802.  
  1803. extern int    help();
  1804.  
  1805. static Command cmdtab[] = {
  1806.     { "close",    closehelp,    bye,        1 },
  1807.     { "^d",    controlhelp,    controld,    1 },
  1808.     { "display",    displayhelp,    display,    0 },
  1809.     { "mode",    modestring,    modecmd,    0 },
  1810.     { "open",    openhelp,    tn,        0 },
  1811.     { "quit",    quithelp,    quit,        0 },
  1812.     { "send",    sendhelp,    sendcmd,    0 },
  1813.     { "set",    sethelp,    setcmd,        0 },
  1814.     { "unset",    unsethelp,    unsetcmd,    0 },
  1815.     { "status",    statushelp,    status,        0 },
  1816.     { "toggle",    togglestring,    toggle,        0 },
  1817.     { "slc",    slchelp,    slccmd,        0 },
  1818.     { "environ",    envhelp,    env_cmd,    0 },
  1819.     { "?",        helphelp,    help,        0 },
  1820.     0
  1821. };
  1822.  
  1823. static char    crmodhelp[] =    "deprecated command -- use 'toggle crmod' instead";
  1824. static char    escapehelp[] =    "deprecated command -- use 'set escape' instead";
  1825.  
  1826. static Command cmdtab2[] = {
  1827.     { "help",    0,        help,        0 },
  1828.     { "escape",    escapehelp,    setescape,    0 },
  1829.     { "crmod",    crmodhelp,    togcrmod,    0 },
  1830.     0
  1831. };
  1832.  
  1833.  
  1834. /*
  1835.  * Call routine with argc, argv set from args (terminated by 0).
  1836.  */
  1837.  
  1838. /*VARARGS1*/
  1839. static
  1840. call(va_alist)
  1841. va_dcl
  1842. {
  1843.     va_list ap;
  1844.     typedef int (*intrtn_t)();
  1845.     intrtn_t routine;
  1846.     char *args[100];
  1847.     int argno = 0;
  1848.  
  1849.     va_start(ap);
  1850.     routine = (va_arg(ap, intrtn_t));
  1851.     while ((args[argno++] = va_arg(ap, char *)) != 0) {
  1852.     ;
  1853.     }
  1854.     va_end(ap);
  1855.     return (*routine)(argno-1, args);
  1856. }
  1857.  
  1858.  
  1859. static char **
  1860. getnextcmd(name)
  1861. char *name;
  1862. {
  1863.     Command *c = (Command *) name;
  1864.  
  1865.     return (char **) (c+1);
  1866. }
  1867.  
  1868. static Command *
  1869. getcmd(name)
  1870. char *name;
  1871. {
  1872.     Command *cm;
  1873.  
  1874.     if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
  1875.     return cm;
  1876.     } else {
  1877.     return (Command *) genget(name, (char **) cmdtab2, getnextcmd);
  1878.     }
  1879. }
  1880.  
  1881. void
  1882. command(top, tbuf, cnt)
  1883.     int top;
  1884.     char *tbuf;
  1885.     int cnt;
  1886. {
  1887.     register Command *c;
  1888.  
  1889.     setcommandmode();
  1890.     if (!top) {
  1891.     putchar('\n');
  1892.     }
  1893.     for (;;) {
  1894.     printf("%s> ", prompt);
  1895.     if (tbuf) {
  1896.         register char *cp;
  1897.         cp = line;
  1898.         while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
  1899.         cnt--;
  1900.         tbuf = 0;
  1901.         if (cp == line || *--cp != '\n' || cp == line)
  1902.         goto getline;
  1903.         *cp = '\0';
  1904.         printf("%s\n", line);
  1905.     } else {
  1906.     getline:
  1907.         if (gets(line) == NULL) {
  1908.         if (feof(stdin) || ferror(stdin)) {
  1909.             (void) quit();
  1910.             /*NOTREACHED*/
  1911.         }
  1912.         break;
  1913.         }
  1914.     }
  1915.     if (line[0] == 0)
  1916.         break;
  1917.     makeargv();
  1918.     if (margv[0] == 0) {
  1919.         break;
  1920.     }
  1921.     c = getcmd(margv[0]);
  1922.     if (Ambiguous(c)) {
  1923.         printf("?Ambiguous command\n");
  1924.         continue;
  1925.     }
  1926.     if (c == 0) {
  1927.         printf("?Invalid command\n");
  1928.         continue;
  1929.     }
  1930.     if (c->needconnect && !connected) {
  1931.         printf("?Need to be connected first.\n");
  1932.         continue;
  1933.     }
  1934.     if ((*c->handler)(margc, margv)) {
  1935.         break;
  1936.     }
  1937.     }
  1938.     if (!top) {
  1939.     if (!connected) {
  1940.         longjmp(toplevel, 1);
  1941.         /*NOTREACHED*/
  1942.     }
  1943.     setconnmode(0);
  1944.     }
  1945. }
  1946.  
  1947. /*
  1948.  * Help command.
  1949.  */
  1950. static
  1951. help(argc, argv)
  1952.     int argc;
  1953.     char *argv[];
  1954. {
  1955.     register Command *c;
  1956.  
  1957.     if (argc == 1) {
  1958.         printf("Commands may be abbreviated.  Commands are:\n\n");
  1959.         for (c = cmdtab; c->name; c++)
  1960.             if (c->help) {
  1961.                 printf("%-*s\t%s\n", HELPINDENT, c->name,
  1962.                                     c->help);
  1963.             }
  1964.         return 0;
  1965.     }
  1966.     while (--argc > 0) {
  1967.         register char *arg;
  1968.         arg = *++argv;
  1969.         c = getcmd(arg);
  1970.         if (Ambiguous(c))
  1971.             printf("?Ambiguous help command %s\n", arg);
  1972.         else if (c == (Command *)0)
  1973.             printf("?Invalid help command %s\n", arg);
  1974.         else
  1975.             printf("%s\n", c->help);
  1976.     }
  1977.     return 0;
  1978. }
  1979.  
  1980. static char *rcname = 0;
  1981. static char rcbuf[128];
  1982.  
  1983. cmdrc(m1, m2)
  1984.     char *m1, *m2;
  1985. {
  1986.     register Command *c;
  1987.     FILE *rcfile;
  1988.     int gotmachine = 0;
  1989.     int l1 = strlen(m1);
  1990.     int l2 = strlen(m2);
  1991.     char m1save[64];
  1992.  
  1993.     strcpy(m1save, m1);
  1994.     m1 = m1save;
  1995.  
  1996.     if (rcname == 0) {
  1997.     rcname = getenv("HOME");
  1998.     if (rcname)
  1999.         strcpy(rcbuf, rcname);
  2000.     else
  2001.         rcbuf[0] = '\0';
  2002.     strcat(rcbuf, "/.telnetrc");
  2003.     rcname = rcbuf;
  2004.     }
  2005.  
  2006.     if ((rcfile = fopen(rcname, "r")) == 0) {
  2007.     return;
  2008.     }
  2009.  
  2010.     for (;;) {
  2011.     if (fgets(line, sizeof(line), rcfile) == NULL)
  2012.         break;
  2013.     if (line[0] == 0)
  2014.         break;
  2015.     if (line[0] == '#')
  2016.         continue;
  2017.     if (gotmachine == 0) {
  2018.         if (isspace(line[0]))
  2019.         continue;
  2020.         if (strncasecmp(line, m1, l1) == 0)
  2021.         strncpy(line, &line[l1], sizeof(line) - l1);
  2022.         else if (strncasecmp(line, m2, l2) == 0)
  2023.         strncpy(line, &line[l2], sizeof(line) - l2);
  2024.         else
  2025.         continue;
  2026.         gotmachine = 1;
  2027.     } else {
  2028.         if (!isspace(line[0])) {
  2029.         gotmachine = 0;
  2030.         continue;
  2031.         }
  2032.     }
  2033.     makeargv();
  2034.     if (margv[0] == 0)
  2035.         continue;
  2036.     c = getcmd(margv[0]);
  2037.     if (Ambiguous(c)) {
  2038.         printf("?Ambiguous command: %s\n", margv[0]);
  2039.         continue;
  2040.     }
  2041.     if (c == 0) {
  2042.         printf("?Invalid command: %s\n", margv[0]);
  2043.         continue;
  2044.     }
  2045.     /*
  2046.      * This should never happen...
  2047.      */
  2048.     if (c->needconnect && !connected) {
  2049.         printf("?Need to be connected first for %s.\n", margv[0]);
  2050.         continue;
  2051.     }
  2052.     (*c->handler)(margc, margv);
  2053.     }
  2054.     fclose(rcfile);
  2055. }
  2056.  
  2057. #if    defined(SRCRT) && defined(IPPROTO_IP)
  2058.  
  2059. /*
  2060.  * Source route is handed in as
  2061.  *    [!]@hop1@hop2...[@|:]dst
  2062.  * If the leading ! is present, it is a
  2063.  * strict source route, otherwise it is
  2064.  * assmed to be a loose source route.
  2065.  *
  2066.  * We fill in the source route option as
  2067.  *    hop1,hop2,hop3...dest
  2068.  * and return a pointer to hop1, which will
  2069.  * be the address to connect() to.
  2070.  *
  2071.  * Arguments:
  2072.  *    arg:    pointer to route list to decipher
  2073.  *
  2074.  *    cpp:     If *cpp is not equal to NULL, this is a
  2075.  *        pointer to a pointer to a character array
  2076.  *        that should be filled in with the option.
  2077.  *
  2078.  *    lenp:    pointer to an integer that contains the
  2079.  *        length of *cpp if *cpp != NULL.
  2080.  *
  2081.  * Return values:
  2082.  *
  2083.  *    Returns the address of the host to connect to.  If the
  2084.  *    return value is -1, there was a syntax error in the
  2085.  *    option, either unknown characters, or too many hosts.
  2086.  *    If the return value is 0, one of the hostnames in the
  2087.  *    path is unknown, and *cpp is set to point to the bad
  2088.  *    hostname.
  2089.  *
  2090.  *    *cpp:    If *cpp was equal to NULL, it will be filled
  2091.  *        in with a pointer to our static area that has
  2092.  *        the option filled in.  This will be 32bit aligned.
  2093.  * 
  2094.  *    *lenp:    This will be filled in with how long the option
  2095.  *        pointed to by *cpp is.
  2096.  *    
  2097.  */
  2098. unsigned long
  2099. sourceroute(arg, cpp, lenp)
  2100. char    *arg;
  2101. char    **cpp;
  2102. int    *lenp;
  2103. {
  2104.     static char lsr[44];
  2105.     char *cp, *cp2, *lsrp, *lsrep, *index();
  2106.     register int tmp;
  2107.     struct in_addr sin_addr;
  2108.     register struct hostent *host = 0;
  2109.     register char c;
  2110.  
  2111.     /*
  2112.      * Verify the arguments, and make sure we have
  2113.      * at least 7 bytes for the option.
  2114.      */
  2115.     if (cpp == NULL || lenp == NULL)
  2116.         return((unsigned long)-1);
  2117.     if (*cpp != NULL && *lenp < 7)
  2118.         return((unsigned long)-1);
  2119.     /*
  2120.      * Decide whether we have a buffer passed to us,
  2121.      * or if we need to use our own static buffer.
  2122.      */
  2123.     if (*cpp) {
  2124.         lsrp = *cpp;
  2125.         lsrep = lsrp + *lenp;
  2126.     } else {
  2127.         *cpp = lsrp = lsr;
  2128.         lsrep = lsrp + 44;
  2129.     }
  2130.  
  2131.     cp = arg;
  2132.  
  2133.     /*
  2134.      * Next, decide whether we have a loose source
  2135.      * route or a strict source route, and fill in
  2136.      * the begining of the option.
  2137.      */
  2138.     if (*cp == '!') {
  2139.         cp++;
  2140.         *lsrp++ = IPOPT_SSRR;
  2141.     } else
  2142.         *lsrp++ = IPOPT_LSRR;
  2143.  
  2144.     if (*cp != '@')
  2145.         return((unsigned long)-1);
  2146.  
  2147.     lsrp++;        /* skip over length, we'll fill it in later */
  2148.     *lsrp++ = 4;
  2149.  
  2150.     cp++;
  2151.  
  2152.     sin_addr.s_addr = 0;
  2153.  
  2154.     for (c = 0;;) {
  2155.         if (c == ':')
  2156.             cp2 = 0;
  2157.         else for (cp2 = cp; c = *cp2; cp2++) {
  2158.             if (c == ',') {
  2159.                 *cp2++ = '\0';
  2160.                 if (*cp2 == '@')
  2161.                     cp2++;
  2162.             } else if (c == '@') {
  2163.                 *cp2++ = '\0';
  2164.             } else if (c == ':') {
  2165.                 *cp2++ = '\0';
  2166.             } else
  2167.                 continue;
  2168.             break;
  2169.         }
  2170.         if (!c)
  2171.             cp2 = 0;
  2172.  
  2173.         if ((tmp = inet_addr(cp)) != -1) {
  2174.             sin_addr.s_addr = tmp;
  2175.         } else if (host = gethostbyname(cp)) {
  2176.             memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
  2177.         } else {
  2178.             *cpp = cp;
  2179.             return(0);
  2180.         }
  2181.         memcpy(lsrp, (char *)&sin_addr, 4);
  2182.         lsrp += 4;
  2183.         if (cp2)
  2184.             cp = cp2;
  2185.         else
  2186.             break;
  2187.         /*
  2188.          * Check to make sure there is space for next address
  2189.          */
  2190.         if (lsrp + 4 > lsrep)
  2191.             return((unsigned long)-1);
  2192.     }
  2193.     if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
  2194.         *cpp = 0;
  2195.         *lenp = 0;
  2196.         return((unsigned long)-1);
  2197.     }
  2198.     *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
  2199.     *lenp = lsrp - *cpp;
  2200.     return(sin_addr.s_addr);
  2201. }
  2202. #endif
  2203.  
  2204. #if    defined(NOSTRNCASECMP)
  2205. strncasecmp(p1, p2, len)
  2206. register char *p1, *p2;
  2207. int len;
  2208. {
  2209.     while (len--) {
  2210.     if (tolower(*p1) != tolower(*p2))
  2211.        return(tolower(*p1) - tolower(*p2));
  2212.     if (*p1 == '\0')
  2213.         return(0);
  2214.     p1++, p2++;
  2215.     }
  2216.     return(0);
  2217. }
  2218. #endif
  2219.